package ru.fadeev.crammer.data;

import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Vector;

import ru.fadeev.crammer.DatabaseManager;
import ru.fadeev.crammer.GFIndicesStorage;
import ru.fadeev.crammer.ProgressBar;


/**
 * PhrasesCorpus class represents one of the data entities of Crammer 
 * program. PhrasesCorpus consists of PhrasesBatches, PhrasesBatches consists
 * of Phrases. PhrasesCorpus contains all phrases, any of them can be used in 
 * Gaps Filling Test. Phrases can be added to PhrasesCorpus from local files 
 * via Settings Dialog, or via internet connection from PhrasesBank 
 * (server that holds a lot of phrases).
 * @author Konstantin Fadeyev
 *
 */
public class PhrasesCorpus {

	/** 
	 * Array of PhrasesBatch objects 
	 */
	private Vector<PhrasesBatch> batches;
	
	
	/**
	 * Constructs PhrasesCorpus
	 */
	public PhrasesCorpus() {
		batches = null;
	}
	
	
	/**
	 * Adds batch to corpus without saving to database.
	 * @param batch
	 */
	public void addBatch(PhrasesBatch batch) {
		if (batches == null) {
			loadBatches();
		}
		batches.addElement(batch);
	}
	
	
	/**
	 * Exports PhrasesBatches to text file. 
	 * File will consist one phrase per line.
	 * @param file text file
	 * @param batchIndices indices of PhrasesBatches to export
	 * @param progressBar progress bar
	 */
	public void exportBatchesToFile(File file, int[] batchIndices, 
			ProgressBar progressBar) {
		try {
	    	Connection connection = DatabaseManager.getConnection();
	        FileWriter fileWriter;
	        file.createNewFile();
	        fileWriter = new FileWriter(file);
            PrintWriter bw = new PrintWriter(fileWriter);
	    	int recordCount = 0;
	        for(int i=0; i < batchIndices.length; i++) {
	        	PhrasesBatch batch = getBatch(batchIndices[i]); 
	        	Statement statement = connection.createStatement();
	    		ResultSet resultSet = statement.executeQuery(
	    				"SELECT PHRASE_TEXT FROM PHRASE " +
		    			"WHERE BATCH_ID = " + batch.getId()
		    			);
	        	while(resultSet.next()) {
	        		recordCount++;
	        		progressBar.updatePBValue(recordCount);
	        		bw.println(resultSet.getString(1));
	        	}
	    		statement.close();
	        }      
	        fileWriter.close();
	    	connection.close();
		} catch (Exception e) {
			e.printStackTrace();
		}	
	}
	
	
	/**
	 * Returns batch specified by index
	 * @param index index of batch in the PhrasesCorpus
	 * @return batch specified by index
	 */
	public PhrasesBatch getBatch(int index) {
		if (batches == null) {
			loadBatches();
		}
		return (PhrasesBatch)batches.elementAt(index);
	}
	
	
	/**
	 * Returns total number of phrases in the corpus 
	 * @return total phrases number in the corpus
	 */
	public int getPhrasesCount() {
		int result = 0;
		for(int i = 0; i < size(); i++) {
			PhrasesBatch batch = (PhrasesBatch)batches.elementAt(i);
			result = result + batch.getPhrasesCount();
		}
		return result;
	}
	
	
	/**
	 * Loads batches from database. Used only by internal functions. 
	 * Batches are loaded only at the moment when some outer object asks 
	 * for them, not any time sooner. Loads only batches information, doesn't
	 * load phrases.
	 */
	protected void loadBatches() {
		batches = new Vector<PhrasesBatch>();
		try {
			Connection connection = DatabaseManager.getConnection();      
			Statement statement = 
				connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
			          ResultSet.CONCUR_READ_ONLY);
			ResultSet resultSet = statement.executeQuery(
					"SELECT ID, NAME, CREATE_DATE " +
        			"FROM PHRASES_BATCH"      			
        			);	
        	while(resultSet.next()) {
        		int id = resultSet.getInt(1);
        		String name = resultSet.getString(2);
        		Timestamp create_date = resultSet.getTimestamp(3);
        		PhrasesBatch newBatch = new PhrasesBatch(id, name, 
        				create_date.getTime());
        		batches.addElement(newBatch);
        	}
        	statement.close();
        	connection.close();
		} catch (Exception e) {
	        e.printStackTrace();
	    }	
	}

	
	/**
	 * Loads some statistics for all batches without loading phrases.
	 * Right now statistics is only phrasesCount for batch.
	 * @param progressBar
	 */
	public void loadStatistics(ProgressBar progressBar) {
		if (batches == null) {
			loadBatches();
		}
		try {
			Connection connection = DatabaseManager.getConnection();
			progressBar.showPBDeterminate(size(), "loading..");
			int progressBarValue = 0;
        	for(int i = 0; i < size(); i++) {
        		PhrasesBatch batch = getBatch(i);
        		batch.loadStatistics(connection);
        		progressBar.updatePBValue(++progressBarValue);
        	}
        	progressBar.hidePB();
        	connection.close();
		} catch (Exception e) {
	        e.printStackTrace();
	    }	
	}	
	
	/**
	 * Removes batches and all related information from corpus and from 
	 * database.
	 * @param indices indices of batches in corpus
	 * @param storage object of GFIndicesStorage
	 */
	public synchronized void removeBatches(int[] indices, 
											GFIndicesStorage storage) {		
		for (int i = 0; i < indices.length; i++) {
			PhrasesBatch batch = getBatch(indices[i]);
			batch.deleteFromDB(storage);
		}		
		for(int i=indices.length-1; i>=0; i--) {
			batches.remove(indices[i]);
		}
	}	
	
	/**
	 * Returns number of PhrasesBatches in the corpus
	 * @return number of PhrasesBatches in the corpus
	 */
	public int size() {
		if (batches == null) {
			loadBatches();
		}
		return batches.size();
	}
	
}
